﻿using Indt.Components;
using Microsoft.Devices;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Info;
using Microsoft.Phone.Shell;
using Microsoft.Xna.Framework.Media;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using TakePhotoTogether.Controller;
using TakePhotoTogether.Dao;
using TakePhotoTogether.ImageProcessing;
using TakePhotoTogether.Model;
using TakePhotoTogether.Resources;
using TakePhotoTogether.Utils;
using TakePhotoTogether.View;
using Windows.Networking.Proximity;
using Windows.Networking.Sockets;
using Windows.Phone.Media.Capture;
using Windows.System.Threading;
using System.Windows.Input;
using Microsoft.Expression.Interactivity.Core;

namespace TakePhotoTogether
{
    public enum ViewState
    {
        SplitView = 1,
        FullView = 2,
        None = 3,
        FullViewConnected = 4
    }

    public partial class MainPage : PhoneApplicationPage
    {
        private const string DEBUG_TAG = "TakePhotoTogether.MainPage => ";
        public static Boolean PhotoSecurityLock = false;

        private Boolean BluetoothEnabled
        {
            get { return MainController.Singleton.IsBluetoothEnabled; }
            set { MainController.Singleton.IsBluetoothEnabled = value; }
        }

        public bool FrontCameraOn { get; private set; }
        private bool capturing = false;
        private bool capturingSemaphore = false;
        private readonly Storyboard shootView;

        private bool WasConnected = false;
        private string currentState;
        private bool isConnected = false;
        private bool isConnecting = false;
        private StateDictionary stateDictionary = new StateDictionary();
        private readonly Storyboard storyBoard1 = new Storyboard();
        private readonly DoubleAnimation doubleAnimation1 = new DoubleAnimation();
        private readonly TimeSpan timeSpan = TimeSpan.FromSeconds(3d);      // 3 sec  
        private readonly Storyboard storyBoard2 = new Storyboard();
        private readonly DoubleAnimation doubleAnimation2 = new DoubleAnimation();
        private readonly TimeSpan timeSpan2 = TimeSpan.FromSeconds(1d);     // 1 sec  

        private readonly WriteableBitmap partnerBitmap = new WriteableBitmap(398, 480);
        private bool peerFinderCompleted;
        private CameraCaptureSequence photoSequence;

        public CameraSensorLocation sensor = CameraSensorLocation.Back;

        private readonly MediaLibrary library = new MediaLibrary();
        private PhotoCaptureDevice _photoCaptureDevice = null;
        private readonly Semaphore _cameraSemaphore = new Semaphore(1, 1);

        /// <summary> Final result of photo taken on Split mode</summary>
        private readonly CVImage finalPhotoSplitMode = new CVImage(800, 480);
        /// <summary> Store partner photo taken on Split mode </summary>
        private readonly CVImage partnerPhotoSplitMode = new CVImage(398, 480);
        /// <summary> Store photos taken on Split mode </summary>
        private readonly CVImage cameraPhotoSplitMode = new CVImage(640, 480);

        /// <summary> Final result of photo taken on Full mode</summary>
        private CVImage cameraPhotoFullMode;
        private CVImage croppedPhotoFullMode;
        private CVImage croppedPhotoFullModeConnected;
        private readonly CVImage resizedPhotoFullMode = new CVImage(800, 480);

        private const string myViewState = "MyView";
        private const string splitViewState = "SplitView";
        private const string preTapState = "PreTap";
        private const string connectingState = "Connecting";
        private const string connectingStateSplit = "ConnectingSplit";
        private const string preTapStateSplit = "PreTapSplit";
        private const string connectedState = "Connected";
        private const string connectedStateSplit = "ConnectedSplit";
        private const string noTapState = "NoTap";
        private const string noTapStateSplit = "NoTapSplit";

        #region Animation-related variables
        private readonly Storyboard circleControlTextInStoryboard;
        private readonly Storyboard circleControlTextInOutStoryboard;
        private readonly Storyboard myViewStoryboard;
        private readonly  Storyboard circleControlStoryboard;
        private readonly DoubleAnimation myViewAnimation;
        private readonly DoubleAnimation myFriendsViewAnimation;
        private readonly DoubleAnimation mySplitViewAnimation;
        private readonly  DoubleAnimation circleControlOpacityAnimation;    
        private readonly  DoubleAnimation circleControlTransformAnimation;
        #endregion

        private float fullViewWidth;
        private float splitViewWidth;


        #region observer-related variables
        private Thread batteryObserver;
        private Thread bluetoothObserver;
        private bool messageBatteryisShowed;
        private bool messageBatteryCritcalLowisShowed;
        #endregion

        private Windows.Foundation.Size fullModeCameraResolution;
        private Windows.Foundation.Size splitModeCameraResolution;

        private bool isInitializingCamera = false;
        private bool flick = true;
        private bool stateConnected = false;
        private bool fromSplit = false;

        public static Popup Waiting;


        public MainPage()
        {
            InitializeComponent();
            
            MainController.Singleton.SetCurrentScreen("MainPage", null);

            Dispatcher.BeginInvoke(() =>
            {
                NavigationService.RemoveBackEntry();
            });

            fadeSetUp();

            FrontCameraOn = true;
            shootView = Resources["ClickAnimation"] as Storyboard;
            CameraSound.Source = new Uri("/CameraShutter.mp3",UriKind.Relative);
            CameraButtons.ShutterKeyReleased += CameraButtons_ShutterKeyReleased;

            MainController.Singleton.OnPeerFound += OnPeerFound;
            MainController.Singleton.OnPeerStarted += OnPeerStarted;
            MainController.Singleton.OnPeerFinderCompleted += OnPeerFinderCompleted;
            MainController.Singleton.OnPeerFailed += OnPeerFailed;
            MainController.Singleton.OnPeerCanceled += OnPeerCanceled;

            MainController.Singleton.OnSocketConnectionDispose += onSocketDispose;

            MainController.Singleton.OnRemoteUserFinishedConnection += OnRemoteUserFinishedConnection;

            VisualStateGroup.CurrentStateChanged += VisualStateGroup_CurrentStateChanged;

            MainController.Singleton.OnStreamDataReceived = OnFrameReceived;
            MainController.Singleton.OnStreamDataError = onStreamError;

            CircleControl.PartnerImage.Source = partnerBitmap;
            MyFriendsView1.Source = partnerBitmap;

            CamerasGrid.Loaded += onCamerasGridLoaded;
            CamerasGrid.ManipulationStarted += onCamerasGridManipulationStarted;
            CamerasGrid.ManipulationDelta += onCamerasGridManipulationDelta;
            CamerasGrid.ManipulationCompleted += onCamerasGridManipulationCompleted;

            myViewStoryboard = CamerasGrid.Resources["MyViewStoryboard"] as Storyboard;
            myViewAnimation = MyViewAnimation;
            myFriendsViewAnimation = new DoubleAnimation(); //MyFriendsViewAnimation;
            mySplitViewAnimation = MySplitViewAnimation;

            Duration duration = new Duration(TimeSpan.FromSeconds(0.2d));
            IEasingFunction easing = new ExponentialEase { Exponent = 8 };
            myViewAnimation.Duration = duration;
            myViewAnimation.EasingFunction = easing;
            myFriendsViewAnimation.Duration = duration;
            myFriendsViewAnimation.EasingFunction = easing;
            mySplitViewAnimation.Duration = duration;
            mySplitViewAnimation.EasingFunction = easing;
            myViewStoryboard.Completed += onMyViewStoryboardCompleted;
            
            circleControlStoryboard = CircleControl.CircleControlStoryboard;
            circleControlOpacityAnimation = CircleControl.CircleControlOpacityAnimation;
            circleControlTransformAnimation = CircleControl.CircleControlTransformAnimation;
            circleControlTextInStoryboard = CircleControl.TextIn;
            circleControlTextInOutStoryboard = CircleControl.TextInOut;

            circleControlOpacityAnimation.Duration = duration;
            circleControlOpacityAnimation.EasingFunction = easing;
            circleControlTransformAnimation.Duration = duration;
            circleControlTransformAnimation.EasingFunction = easing;
           
            AppBar.EventForPageNavigation += new EventHandler(AppBar_NavigateToPageEvent);

#if DEBUG
            FrameRateTextBlock.Visibility = Visibility.Visible;


            Debug.WriteLine("Device Name: " + Microsoft.Phone.Info.DeviceStatus.DeviceName);
#endif
            batteryObserver = new Thread(new ThreadStart(WatchBattery));
            batteryObserver.IsBackground = true;
            batteryObserver.Start();
            messageBatteryisShowed = false;
            messageBatteryCritcalLowisShowed = false;
            Debug.WriteLine("Battery Watcher Start*************");

            bluetoothObserver = new Thread(new ThreadStart(WatcherBlueTooth));
            bluetoothObserver.IsBackground = true;
            bluetoothObserver.Start();
#if DEBUG
            Debug.WriteLine("Memory Watcher Start *************");

            Debug.WriteLine("Front Camera Veirfication Initialize *******");
#endif
            if (!DeviceInfo.IsDeviceHasFrontCamera()) {
               
                ViewNewMenu.CollapsedFrontCameraButton();
            }
#if DEBUG
            Debug.WriteLine("Front Camera Verification Finished");
            Debug.WriteLine("Bluetooth Verification");
#endif
            HandleErrorOnDetectConnection();
        }

        private void OnRemoteUserFinishedConnection()
        {
            UpdateMessageForUI(AppResources.Error_Exit_Friend_Message, AppResources.Error_Exit_Friend_Message_Title);
        }

        private void HandleErrorOnDetectConnection()
        {
            if (MainController.Singleton.IsPeerFound)
            {
                // If peer is already found then must set UI to connecting state
                // Even peer is already connected must set UI to connecting state
                // Because only when a frame is received that must connected state 
                // must be updated
                Dispatcher.BeginInvoke(() =>
                {
                    if (getViewState() == ViewState.SplitView)
                    {
                        ChangeState(stateDictionary.PreTapSlit());
                        ChangeState(stateDictionary.ConnectingSplit());
                    }
                    else
                    {
                        ChangeState(stateDictionary.PreTap());
                        ChangeState(stateDictionary.Connecting());
                    }
                });
            }
            else
            {
                Dispatcher.BeginInvoke(() =>
                {
                    if (getViewState() == ViewState.SplitView)
                    {
                        ChangeState(stateDictionary.PreTapSlit());
                    }
                    else
                    {
                        ChangeState(stateDictionary.PreTap());
                    }
                });
            }
        }

        private void WatchBattery()
        {
            int IntervalSleep = 0;
           
              
                while (true)
                {
                    try
                    {
                        int batteryPercent = DeviceInfo.getBatteryLevelPercent();

                        if (batteryPercent > 70)
                        {
                            IntervalSleep = 8000;//Time to next verification of battery level
                            if (MainController.Singleton.NoTap)
                            {
                                MainController.Singleton.NoTap = false;
                                ChangeState(stateDictionary.PreTap());
                            }
                        }
                        else if ((batteryPercent > 30) && (batteryPercent <= 70))
                        {
                            IntervalSleep = 150000;
                            if (MainController.Singleton.NoTap)
                            {
                                MainController.Singleton.NoTap = false;
                                ChangeState(stateDictionary.PreTap());

                            }

                        }
                        else if ((batteryPercent <= 30) && (batteryPercent > 25))
                        {
                            if (!messageBatteryisShowed)
                            {
                                UpdateMessageForUI(AppResources.Error_Battery_Low_Message, AppResources.Error_Battery_Low_Message_Title);
                                messageBatteryisShowed = !messageBatteryisShowed;
                            }
                            MainController.Singleton.NoTap = true;
                            IntervalSleep = 60000;
                        }
                        else
                        {
                            if (!messageBatteryCritcalLowisShowed)
                            {

                                UpdateMessageForUI(AppResources.Error_Battery_Critical_Message, AppResources.Error_Battery_Critical_Message_Title);
                                messageBatteryCritcalLowisShowed = !messageBatteryCritcalLowisShowed;
                                if (stateDictionary.getInstance().isSplit)
                                    ChangeState(stateDictionary.NoTapSplit());
                                else
                                    ChangeState(stateDictionary.NoTap());


                            }
                            MainController.Singleton.NoTap = true;
                            IntervalSleep = 120000;

                        }
                        Debug.WriteLine("Battery Verification => " + batteryPercent);
                        batteryObserver.Join(IntervalSleep);
                    }
                    catch (Exception errorBattery)
                    {
                        Debug.WriteLine("Error at Battery Verification =>" + errorBattery.Message);
                    }
                }
           
        }

        private void UpdateMessageForUI(string message, string title) {
           
            Dispatcher.BeginInvoke((Action)(() =>
            {
                MessageBox.Show(message, title, MessageBoxButton.OK);
            }));

            
        }

        private void WatcherBlueTooth() {
            while (true)
            {
                if (!BluetoothEnabled)
                {
                    UpdateMessageForUI(AppResources.Error_Bluetooth_Turn_Off_Message, AppResources.Error_Bluetooth_Turn_Off_Message_Title);
                    Dispatcher.BeginInvoke(() =>
                        {
                            ChangeState(stateDictionary.PreTap());
                        });
                    BluetoothEnabled = true;
                }
                
                bluetoothObserver.Join(1000);
            }
        }

        private void onCamerasGridLoaded(object sender, RoutedEventArgs e)
        {
            CamerasGrid.Loaded -= onCamerasGridLoaded;
            fullViewWidth = (float)CamerasGrid.ActualWidth;
            splitViewWidth = fullViewWidth / 2f - 2f;
        }

        private void onMyViewStoryboardCompleted(object sender, EventArgs e)
        {
            if (getViewState() == ViewState.SplitView)
            {
                MyFriendsView1.Visibility = Visibility.Visible;
                CircleControl.Visibility = Visibility.Collapsed;
            }
            else
            {
                MyFriendsView1.Visibility = Visibility.Collapsed;
                CircleControl.Visibility = Visibility.Visible;
            }
        }

        private enum DragLock
        {
            Unset,
            Free,
            Vertical,
            Horizontal,
        }

        private DragLock dragLock;
        private bool dragging;
        private readonly System.Windows.Controls.Orientation orientation = System.Windows.Controls.Orientation.Horizontal;

        private void onCamerasGridManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
        {
            if (capturingSemaphore)
            {
                return;
            }

            if (ViewNewMenu.CurrentState == AppBar.State.Open)
            {
                e.Complete();
                ViewNewMenu.UpdateState();
                return;
            }
          if (getViewState() == ViewState.SplitView)
            {
                flick = false;
            }
            e.Handled = true;
            dragLock = DragLock.Unset;
            dragging = false;
           
            MyFriendsView1.Visibility = Visibility.Visible;
            CircleControl.Visibility = Visibility.Visible;
        }

        private void relaseMouseCapture()
        {
            MyView1.ReleaseMouseCapture();
            MyFriendsView1.ReleaseMouseCapture();
            CamerasGrid.ReleaseMouseCapture();
        }

        private void onCamerasGridManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            if (capturingSemaphore)
            {
                return;
            }

            if (!dragging)
                relaseMouseCapture();

            dragging = true;

            if (dragLock == DragLock.Unset)
            {
                double angle = angleFromVector(e.CumulativeManipulation.Translation.X, e.CumulativeManipulation.Translation.Y) % 180;
                dragLock = angle <= 45 || angle >= 135 ? DragLock.Horizontal : DragLock.Vertical;
            }

            e.Handled = true;

            if (dragLock == DragLock.Horizontal && e.DeltaManipulation.Translation.X != 0 && orientation == System.Windows.Controls.Orientation.Horizontal ||
                dragLock == DragLock.Vertical && e.DeltaManipulation.Translation.Y != 0 && orientation == System.Windows.Controls.Orientation.Vertical)
            {
                drag(e);
            }
        }

        private void onCamerasGridManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
        {

            if (capturingSemaphore)
            {
                return;
            }

            if (dragLock != DragLock.Horizontal)
                return;


            
            dragLock = DragLock.Unset;
            dragging = false;
            e.Handled = true;
            double x = e.ManipulationOrigin.X;
            
            //bool flick = Math.Abs(e.FinalVelocities.LinearVelocity.X) > 80f;
            double width = MyView1.ActualWidth;
            double finalWidth = fullViewWidth;
            CompositeTransform circleControlTransform = CircleControl.LayoutRoot.RenderTransform as CompositeTransform;
            //CompositeTransform transform = MyView1.RenderTransform as CompositeTransform;
            //double translateX = transform.TranslateX;

            if (flick)
            {
                double angle = angleFromVector(e.FinalVelocities.LinearVelocity.X, e.FinalVelocities.LinearVelocity.Y);
                if (angle <= 45 || angle >= 315)
                {
                    angle = 0;
                }
                else if (angle >= 135 && angle <= 225)
                {
                    angle = 180;
                }

                relaseMouseCapture();

                int intAngle = (int)angle;
                ViewState state = getViewState();
                if (intAngle == 0)
                {
                    if (state != ViewState.FullView)
                    {
                       
                        if (isConnected)
                        {
                            ChangeState(stateDictionary.ConnectedSplit());
                            fromSplit = true;
                        }
                        else if (isConnecting)
                        {
                            ChangeState(stateDictionary.ConnectingSplit());
                        }
                        else
                        {
                            ChangeState(stateDictionary.PreTapSlit());

                        }
                    }
                    else 
                    {

                        if (isConnected)
                        {
                            if (WasConnected)
                            {
                                ChangeState(stateDictionary.MyView());
                            }
                            else
                            {
                                ChangeState(stateDictionary.Connected());
                                WasConnected = true;
                            }

                        }
                        else if (isConnecting)
                        {
                            ChangeState(stateDictionary.Connecting());

                        }
                        else
                        {
                            ChangeState(stateDictionary.PreTap());

                        }
                    
                    }
                      
                    finalWidth = fullViewWidth;
                }
                else if (intAngle == 180)
                {
                    if (state != ViewState.SplitView)
                    {

                        if (isConnected)
                        {
                            ChangeState(stateDictionary.ConnectedSplit());
                            fromSplit = true;
                        }
                        else if (isConnecting)
                        {
                            ChangeState(stateDictionary.ConnectingSplit());

                        }
                        else
                        {
                            ChangeState(stateDictionary.PreTapSlit());

                        }
                    }
                    else { 
                        if (isConnected)
                        {
                            if (WasConnected)
                            {
                                ChangeState(stateDictionary.MyView());
                            }
                            else
                            {
                                ChangeState(stateDictionary.Connected());
                                WasConnected = true;
                            }

                        }
                        else if (isConnecting)
                        {
                            ChangeState(stateDictionary.Connecting());

                        }
                        else
                        {
                            ChangeState(stateDictionary.PreTap());
                        }
                    
                    }
                    finalWidth = splitViewWidth;
                }
             
            }
            else
            {
                if (width < splitViewWidth + (fullViewWidth - splitViewWidth) / 2f)
                {
                    finalWidth = splitViewWidth;
                    if (isConnected)
                    {
                        ChangeState(stateDictionary.ConnectedSplit());
                        fromSplit = true;
                    }
                    else if (isConnecting)
                    {
                        ChangeState(stateDictionary.ConnectingSplit());

                    }
                    else
                    {
                        ChangeState(stateDictionary.PreTapSlit());

                    }
                }
                else
                {
                    finalWidth = fullViewWidth;
                    if (isConnected)
                    {
                        if (WasConnected)
                        {
                            ChangeState(stateDictionary.MyView());
                        }
                        else
                        {
                            ChangeState(stateDictionary.Connected());
                            WasConnected = true;
                        }
                    }
                    else if (isConnecting)
                    {
                        ChangeState(stateDictionary.Connecting());

                    }
                    else
                    {
                        ChangeState(stateDictionary.PreTap());

                    }
                }
             
            }

           
            if (isConnected)
            {
                myViewStoryboard.Stop();
                circleControlStoryboard.Stop();
            }

            myViewAnimation.From = width;
            myViewAnimation.To = finalWidth;
            mySplitViewAnimation.From = splitGrid.Width;
            mySplitViewAnimation.To = finalWidth == fullViewWidth ? 0d : splitViewWidth;
            myViewStoryboard.SeekAlignedToLastTick(TimeSpan.Zero);
            myViewStoryboard.Begin();

            circleControlOpacityAnimation.From = CircleControl.LayoutRoot.Opacity;
            circleControlOpacityAnimation.To = finalWidth == fullViewWidth ? 1f : 0f;
            circleControlTransformAnimation.From = circleControlTransform.TranslateX;
            circleControlTransformAnimation.To = -(fullViewWidth - finalWidth);
            circleControlStoryboard.SeekAlignedToLastTick(TimeSpan.Zero);
            circleControlStoryboard.Begin();
        }

        private double angleFromVector(double x, double y)
        {
            double num = Math.Atan2(y, x);
            if (num < 0)
            {
                num = 2 * Math.PI + num;
            }
            return num * 360 / (2 * Math.PI);
        }

        private void drag(System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            if (capturingSemaphore)
            {
                return;
            }

            if (myViewStoryboard.GetCurrentState() == ClockState.Active)
                return;
            float delta = (float)e.DeltaManipulation.Translation.X;
            MyView1.Width = Microsoft.Xna.Framework.MathHelper.Clamp((float)MyView1.ActualWidth + delta,
                                                                     splitViewWidth,
                                                                     fullViewWidth);
            //MyFriendsView1.Width = Microsoft.Xna.Framework.MathHelper.Clamp((float)fullViewWidth - (float)MyView1.Width - (fullViewWidth / 2f - splitViewWidth) * 2f,
            //                                                                       0f,
            //                                                                       splitViewWidth);

            splitGrid.Width = Microsoft.Xna.Framework.MathHelper.Clamp((float)fullViewWidth - (float)MyView1.Width - (fullViewWidth / 2f - splitViewWidth) * 2f,
                                                                                   0f,
                                                                                   splitViewWidth);

            SplitGridAnimation.Value = isConnected ? Visibility.Collapsed : Visibility.Visible;
            
            //CompositeTransform transform = MyView1.RenderTransform as CompositeTransform;
            //double translate = transform.TranslateX;
            //translate = Microsoft.Xna.Framework.MathHelper.Clamp((float)translate + delta, -402f, 0f);
            //transform.TranslateX = translate;

            (CircleControl.LayoutRoot.RenderTransform as CompositeTransform).TranslateX = -(fullViewWidth - MyView1.Width);
            CircleControl.LayoutRoot.Opacity = 1f - (fullViewWidth - MyView1.Width) / splitViewWidth;
        }
        
        public async void frontCameraButton_Click(object sender, EventArgs e)
        {
            if (_cameraSemaphore.WaitOne(500))
            {
                uninitializeCamera();

                FrontCameraOn = false;

                if (sensor == CameraSensorLocation.Back)
                {
                    sensor = CameraSensorLocation.Front;
                    txtCamStates.Visibility = Visibility.Visible;
                    txtCamStates.Opacity = 1; // make it visible  
                    txtCamStates.Text = AppResources.FrontCamera;
                    storyBoard2.Begin();
                    (Application.Current as App).CameraSettings.FlashState = FlashState.Off;
                }
                else
                {
                    sensor = CameraSensorLocation.Back;
                }
                //_photoCaptureDevice.Dispose();
                //_photoCaptureDevice = null;

                await initializeCamera();

                FrontCameraOn = true;

                _cameraSemaphore.Release();
            }
        }

        private void fadeSetUp()
        {
            txtCamStates.Opacity = 0; // make it invisible  

            doubleAnimation1.Duration = timeSpan;   // set the time  
            doubleAnimation1.From = 1;   // visible  
            doubleAnimation1.To = 0; // invisible  
            Storyboard.SetTarget(doubleAnimation1, txtCamStates);    // set the control as the target  
            Storyboard.SetTargetProperty(doubleAnimation1, new PropertyPath("Opacity")); // set the property path to opacity  
            storyBoard1.Children.Add(doubleAnimation1);
            storyBoard1.Completed += storyBoard1_Completed;
            
            doubleAnimation2.Duration = timeSpan2;   // set the time  
            doubleAnimation2.From = 1;   // visible  
            doubleAnimation2.To = 1; // visible  
            Storyboard.SetTarget(doubleAnimation2, txtCamStates);    // set the control as the target  
            Storyboard.SetTargetProperty(doubleAnimation2, new PropertyPath("Opacity")); // set the property path to opacity  
            storyBoard2.Completed += storyBoard2_Completed;
            storyBoard2.Children.Add(doubleAnimation2);
        }

        private void storyBoard1_Completed(object sender, EventArgs e)
        {
            txtCamStates.Visibility = Visibility.Collapsed;
        }

        private void storyBoard2_Completed(object sender, EventArgs e)
        {
            storyBoard1.Begin();    // animate  
        }

     
        private void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
        {
            ViewState state = getViewState();
            Debug.WriteLine(DEBUG_TAG + "CurrentState changed to {0}!!!!", state);

            if (state == ViewState.None)
            {
                MyView1.Width = fullViewWidth;
                MyFriendsView1.Visibility = Visibility.Collapsed;
                CircleControl.Visibility = Visibility.Visible;
                CircleControl.LayoutRoot.Opacity = 1f;
                (CircleControl.LayoutRoot.RenderTransform as CompositeTransform).TranslateX = 0f;
            }
            if (state == ViewState.FullView)
            {
                MyView1.Width = fullViewWidth;
                MyFriendsView1.Visibility = Visibility.Collapsed;
                CircleControl.Visibility = Visibility.Visible;
                CircleControl.LayoutRoot.Opacity = 1f;
                (CircleControl.LayoutRoot.RenderTransform as CompositeTransform).TranslateX = 0f;
            }

            //Send State change to remote
            if (peerFinderCompleted)
            {
                MainController.Singleton.OnMainViewStateChanged(getViewState());
            }
        }

        private async Task takePhoto()
        {
            Debug.WriteLine(DEBUG_TAG + "take photo");

            if (photoSequence == null)
            {
                return;
            }

            using (RandomStream myPhotoStream = new RandomStream(new MemoryStream()))
            {
                myPhotoStream.Seek(0);
                photoSequence.Frames[0].CaptureStream = myPhotoStream;
                    
                ViewState state = getViewState();

                await _photoCaptureDevice.PrepareCaptureSequenceAsync(photoSequence);
                await photoSequence.StartCaptureAsync();

                myPhotoStream.Seek(0);

                CVImage finalPhoto = null;

                StreamImage LastPartnerImage = MainController.Singleton.LastPartnerImage;

                if (state != ViewState.SplitView || LastPartnerImage.imageData == null)
                {
                    cameraPhotoFullMode.SetSource(myPhotoStream.InternStream);


                    PixelUtil.Crop(cameraPhotoFullMode.Width, cameraPhotoFullMode.Height, cameraPhotoFullMode.Pixels,
                          croppedPhotoFullMode.Width, croppedPhotoFullMode.Height, 0, (cameraPhotoFullMode.Height - croppedPhotoFullMode.Height) / 2, croppedPhotoFullMode.Pixels);

                    if (isConnected)
                    {
                        PixelUtil.Resize(croppedPhotoFullMode.Width, croppedPhotoFullMode.Height, croppedPhotoFullMode.Pixels,
                        croppedPhotoFullModeConnected.Width, croppedPhotoFullModeConnected.Height, croppedPhotoFullModeConnected.Pixels);

                        finalPhoto = croppedPhotoFullModeConnected;
                    }
                    else
                    {
                        finalPhoto = croppedPhotoFullMode;
                    }
                }
                else
                {
                    cameraPhotoFullMode.SetSource(myPhotoStream.InternStream);

                    PixelUtil.Resize(cameraPhotoFullMode.Width, cameraPhotoFullMode.Height, cameraPhotoFullMode.Pixels,
                        cameraPhotoSplitMode.Width, cameraPhotoSplitMode.Height, cameraPhotoSplitMode.Pixels);

                    partnerPhotoSplitMode.LoadJpeg(LastPartnerImage.imageData);

                    cameraPhotoSplitMode.ConcatHalfImages(partnerPhotoSplitMode, finalPhotoSplitMode);

                    finalPhoto = finalPhotoSplitMode;
                }

                Debug.WriteLine(DEBUG_TAG + "takePhoto - current view state: " + state);

                if (isConnected)
                {
                    finalPhoto.SavePhoto().SyncPhoto();
                }
                else
                {
                    finalPhoto.SavePhoto();
                }

                finalPhoto = null;
            }

            Debug.WriteLine(DEBUG_TAG + "photo ok");
        }

        private void OnFrameReceived(MemoryStream stream)
        {
            stream.Seek(0, SeekOrigin.Begin);

            partnerBitmap.LoadJpeg(stream);

            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                CamerasGrid.CacheMode = null;
                CamerasGrid.UpdateLayout();
                CamerasGrid.InvalidateMeasure();
                CamerasGrid.InvalidateArrange();

                MyFriendsView1.CacheMode = null;
                MyFriendsView1.Source = null;
                MyFriendsView1.Source = partnerBitmap;
            
                //CircleControl.TextStatus.Text = AppResources.MainView_Circle_Connected;
                if (stateDictionary.getInstance().isSplit)
                {
                    ChangeState(stateDictionary.ConnectedSplit());
                    fromSplit = true;
                }
                else
                {
                    if (!stateConnected)
                    {
                        if (WasConnected)
                        {
                            ChangeState(stateDictionary.MyView());
                        }
                        else
                        {
                            ChangeState(stateDictionary.Connected());
                            WasConnected = true;
                        }
                        stateConnected = true;
                    }
                    else
                    {
                        //ChangeState(stateDictionary.MyView());

                        if (!fromSplit)
                        {
                            ChangeState(stateDictionary.Connected());
                        }
                        else
                        {
                            ChangeState(stateDictionary.MyView());
                        }
                    }
                }
                circleControlTextInOutStoryboard.Begin();
            });
        }

#if DEBUG
        private bool rendering = false;
        private int frameCount = 0;
        private int frameRate = 0;
        private TimeSpan time = TimeSpan.Zero;
        private DateTime lastTime = DateTime.Now;
        private readonly TimeSpan oneSecond = TimeSpan.FromSeconds(1d);

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            DateTime now = DateTime.Now;
            time += now - lastTime;
            lastTime = now;

            frameCount++;

            if (time >= oneSecond)
            {
                frameRate = frameCount;
                frameCount = 0;
                FrameRateTextBlock.Text = frameRate.ToString();
                time = TimeSpan.Zero;
            }
        }
#endif
        private void onStreamError()
        {
            Debug.WriteLine(DEBUG_TAG + "onStreamError");
        }

        private async void ButtonShootMyView_Click(object sender, RoutedEventArgs e)
        {
            await Shoot();
        }

        private async void CameraButtons_ShutterKeyReleased(object sender, EventArgs e)
        {
            await Shoot();
        }

        private async Task Shoot()
        {
            if (!PhotoSecurityLock)
            {
                if (!capturingSemaphore)
                {
                    CameraSound.Play();
                    capturingSemaphore = true;
                    WaitingLabel.Visibility = Visibility.Visible;
                    WaitingProgress.Visibility = Visibility.Visible;

                    ButtonShootMyView.IsEnabled = false;
                    ButtonGallery.IsEnabled = false;
                    ViewNewMenu.IsHitTestVisible = false;
                    
                    shootView.Begin();
                    await takePhoto();
                    
                    capturingSemaphore = false;
                    WaitingLabel.Visibility = Visibility.Collapsed;
                    WaitingProgress.Visibility = Visibility.Collapsed;
                    
                    Dispatcher.BeginInvoke(() =>
                    {
                        ButtonShootMyView.IsEnabled = true;
                        ButtonGallery.IsEnabled = true;
                        ViewNewMenu.IsHitTestVisible = true;
                    });

                }
            }
        }

        private void onSocketDispose()
        {
            Debug.WriteLine("MainPage::OnSocketDispose");

            isConnected = false;
            isConnecting = false;
            peerFinderCompleted = false;
            stateConnected = false;
            fromSplit = false;
            WasConnected = false;

            // Erase partner image
            Array.Clear(partnerBitmap.Pixels, 0, partnerBitmap.Pixels.Length);

            Dispatcher.BeginInvoke(() =>
            {
                if (getViewState() == ViewState.SplitView)
                {
                    ChangeState(stateDictionary.PreTapSlit());
                }
                else
                {
                    ChangeState(stateDictionary.PreTap());
                }
            });
        }

        private void OnPeerStarted()
        {
            Debug.WriteLine("MainPage::OnPeerStarted");

            try
            {
                CameraSound.Source = new Uri("/CameraShutter.mp3", UriKind.Relative);
            }
            catch { }
            
            isConnecting = true;

            Dispatcher.BeginInvoke(() =>
            {
                ChangeState(stateDictionary.PreTap());
            });
         
        }

        private void OnPeerFound()
        {
            Debug.WriteLine("MainPage::OnPeerFound");
            Dispatcher.BeginInvoke(() =>
            {
                if (stateDictionary.getInstance().isSplit)
                {
                    ChangeState(stateDictionary.ConnectingSplit()); 
                }
                else {
                    ChangeState(stateDictionary.Connecting());
                }
            });
        }
      
        private void OnPeerFailed()
        {
            peerFinderCompleted = false;
            isConnecting = false;
        
            Debug.WriteLine(DEBUG_TAG + "OnPeerFailed");
            Dispatcher.BeginInvoke(() =>
            {
                var currentState = currentStateName();

                if (connectingState.Equals(currentState) || connectingStateSplit.Equals(currentState) || 
                    connectedState.Equals(currentState) || connectedStateSplit.Equals(currentState))
                {
                    MessageBox.Show("Unable to connect. Tap the phones again.", "Sorry...", MessageBoxButton.OK);
                    ChangeState(connectingState.Equals(currentState) ? stateDictionary.PreTap() : stateDictionary.PreTapSlit());
                }
            });
        }

        private void OnPeerCanceled()
        {
            Debug.WriteLine(DEBUG_TAG + "OnPeerCanceled");
            Dispatcher.BeginInvoke(() =>
            {
                if (connectingState.Equals(currentStateName()))
                {
                   
                    MessageBox.Show("Partner refused to play.", "Sorry...", MessageBoxButton.OK);
                    ChangeState(stateDictionary.PreTap());
                }
            });
        }

        private void OnPeerFinderCompleted()
        {
            Debug.WriteLine(DEBUG_TAG + "OnPeerFinderCompleted ");
            peerFinderCompleted = true;
          //  VibrateController vibrate = VibrateController.Default;
           // vibrate.Start(TimeSpan.FromMilliseconds(300));

            Dispatcher.BeginInvoke(() =>
            {
                initializeCameraAndServices();
            });
        }

        private void showSystemTray(string message)
        {
            showSystemTray(message, TimeSpan.FromSeconds(3d));
        }

        private void showSystemTray(string message, TimeSpan timeVisible)
        {
            Dispatcher.BeginInvoke(() =>
            {
                SystemTray.ProgressIndicator.Text = message;
                SystemTray.IsVisible = true;
                if (timeVisible != TimeSpan.Zero)
                {
                    ThreadPoolTimer.CreateTimer((timer) =>
                    {
                        Dispatcher.BeginInvoke(() =>
                        {
                            SystemTray.IsVisible = false;
                        });
                    }, timeVisible);
                }
            });
        }

        private string currentStateName()
        {
            return VisualStateGroup.CurrentState != null ? VisualStateGroup.CurrentState.Name : string.Empty;
        }

        private ViewState getViewState()
        {
            string name = currentStateName();
            if (name == myViewState)
            {
                return ViewState.FullView;
            }
            else if (name == splitViewState)
            {
                return ViewState.SplitView;
            }
            else if (name == preTapState) {
                return ViewState.FullView;
            }
            else if (name == connectingState)
            {
                return ViewState.FullView;
            }
            else if (name == connectingStateSplit)
            {
                return ViewState.SplitView;
            }
            else if (name == preTapStateSplit)
            {
                return ViewState.SplitView;
            }
            else if (name == noTapState)
            {
                return ViewState.FullView;
            }
            else if (name == noTapStateSplit)
            {
                return ViewState.SplitView;
            }
            else if (name == connectedState)
            {
                return ViewState.FullView;
            }
            else if (name == connectedStateSplit)
            {
                return ViewState.SplitView;
            }
            return ViewState.None;
        }

        public void flashButton_Click(object sender, EventArgs e)
        {
            CameraSettingsModel cameraSettings = (Application.Current as App).CameraSettings;
            if (cameraSettings.FlashState == FlashState.On)
            {
                cameraSettings.FlashState = FlashState.Off;
                currentState = AppResources.FlashOff;
            }
            else if (cameraSettings.FlashState == FlashState.Off)
            {
                cameraSettings.FlashState = FlashState.Auto;
                currentState = AppResources.FlashAuto;
            }
            else
            {
                cameraSettings.FlashState = FlashState.On;
                currentState = AppResources.FlashOn;
            }
            _photoCaptureDevice.SetProperty(KnownCameraPhotoProperties.FlashMode, cameraSettings.FlashState);
            txtCamStates.Text = currentState;
            txtCamStates.Visibility = Visibility.Visible;
            txtCamStates.Opacity = 1; 
            storyBoard2.Begin(); //[Refatorar, o que é storyBoard2????]
        }

        private void ViewNewMenu_Loaded(object sender, RoutedEventArgs e)
        {
            ViewNewMenu.Loaded -= ViewNewMenu_Loaded;
            ViewNewMenu.SetParent(this);
        }

        private void FTU_Loaded(object sender, RoutedEventArgs e)
        {
            FTU.Loaded -= FTU_Loaded;
            FTU.SetParent(this);
        }

        private void ButtonGallery_Click(object sender, RoutedEventArgs e)
        {
            if (!capturingSemaphore)
            {
                MainController.Singleton.SetCurrentScreen("", null);

               //FTU.UpdateState("Gallery");

                NavigationService.Navigate(new Uri("/View/GalleryPage.xaml", UriKind.RelativeOrAbsolute));
            }
        }
    

        private async Task initializeCamera()
        {
            if (_photoCaptureDevice != null || isInitializingCamera)
                return;
            isInitializingCamera = true;
            try
            {
              //  capturingSemaphore = true;

                var captureResolutions = PhotoCaptureDevice.GetAvailableCaptureResolutions(sensor);

                var previewResolution = PhotoCaptureDevice.GetAvailablePreviewResolutions(sensor).Last();
                _photoCaptureDevice = await PhotoCaptureDevice.OpenAsync(sensor, previewResolution);

                double ratio = 1.0 * previewResolution.Width / previewResolution.Height;

                // Get the maximum resolution of the same preview ratio
                for (int i = 0; i < captureResolutions.Count; i++)
                {
                    Windows.Foundation.Size resolution = captureResolutions[i];

                    Debug.WriteLine("FullModeResolution = " + resolution);
                    if ((resolution.Width / resolution.Height) == ratio)
                    {
                        Debug.WriteLine("FullModeResolution Choosed = " + resolution);
                        fullModeCameraResolution = resolution;
                        break;
                    }
                }

                // Get the minimum resolution of the same preview ratio
                for (int i = captureResolutions.Count - 1; i >= 0; i--)
                {
                    Windows.Foundation.Size resolution = captureResolutions[i];

                    Debug.WriteLine("SplitModeResolution Choosed = " + resolution);
                    if ((resolution.Width / resolution.Height) == ratio)
                    {
                        Debug.WriteLine("SplitModeResolution Choosed = " + resolution);
                        splitModeCameraResolution = resolution;
                        break;
                    }
                }

                cameraPhotoFullMode = new CVImage((int)fullModeCameraResolution.Width, (int)fullModeCameraResolution.Height);
                croppedPhotoFullMode = new CVImage(cameraPhotoFullMode.Width, (int)(cameraPhotoFullMode.Width*0.5625f));
                croppedPhotoFullModeConnected = new CVImage(800, 480);

                foreach (var r in captureResolutions)
                {
                    Debug.WriteLine(DEBUG_TAG + "initialize - avalaible capture resolutions: " + r);
                }

                foreach (var r in PhotoCaptureDevice.GetAvailablePreviewResolutions(sensor))
                {
                    Debug.WriteLine(DEBUG_TAG + "initialize - avalaible preview resolutions: " + r);
                }

                if (sensor == CameraSensorLocation.Back)
                {
                    CameraSettingsModel cameraSettings = (Application.Current as App).CameraSettings;
                    _photoCaptureDevice.SetProperty(KnownCameraPhotoProperties.FlashMode, cameraSettings.FlashState);
                }

                await _photoCaptureDevice.SetCaptureResolutionAsync(fullModeCameraResolution);
                photoSequence = _photoCaptureDevice.CreateCaptureSequence(1);

                await _photoCaptureDevice.SetPreviewResolutionAsync(previewResolution);

                BackgroundVideoBrush.SetSource(_photoCaptureDevice);

                HandleOrientationChanged();

                MainController.Singleton.SetupCamera(_photoCaptureDevice);

             //   capturingSemaphore = false;
            }
            catch
            {
                uninitializeCamera();
            }

            isInitializingCamera = false;
            GC.Collect();
        }

        private void uninitializeCamera()
        {
            if (_photoCaptureDevice != null)
            {
                MainController.Singleton.SetupCamera(null);
                _photoCaptureDevice.Dispose();
                _photoCaptureDevice = null;
            }
            if (photoSequence != null)
            {
                photoSequence = null;
            }
        }

        protected override void OnOrientationChanged(OrientationChangedEventArgs e)
        {
            base.OnOrientationChanged(e);

            HandleOrientationChanged();
        }

        private void HandleOrientationChanged()
        {
            if (_photoCaptureDevice != null)
            {
                double canvasAngle;

                if (Orientation.HasFlag(PageOrientation.LandscapeLeft))
                {
                    canvasAngle = _photoCaptureDevice.SensorRotationInDegrees - 90;
                    MainController.Singleton.OrientationChange = false;
                }
                else if (Orientation.HasFlag(PageOrientation.LandscapeRight))
                {
                    canvasAngle = _photoCaptureDevice.SensorRotationInDegrees + 90;
                    MainController.Singleton.OrientationChange = true;
                }
                else // PageOrientation.PortraitUp
                {
                    canvasAngle = _photoCaptureDevice.SensorRotationInDegrees;
                }

                BackgroundVideoBrush.RelativeTransform = new RotateTransform()
                {
                    CenterX = 0.5,
                    CenterY = 0.5,
                    Angle = canvasAngle
                };

                _photoCaptureDevice.SetProperty(KnownCameraGeneralProperties.EncodeWithOrientation, canvasAngle);
            }
        }

        private async void initializeCameraAndServices()
        {
            if (!isInitializingCamera)
            {
                await initializeCamera();
            }
            else
            {
                while (isInitializingCamera)
                    await Task.Delay(200);
            }

            await Task.Delay(1000);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            MainController.Singleton.SetCurrentScreen("MainPage", null);

            ViewNewMenu.SetFlashState((Application.Current as App).CameraSettings.FlashState);

            // Check to see if the camera is available on the phone.
            if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary) ||
                PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
            {
                if (!peerFinderCompleted)
                {
                    initializeCamera();

                    HandleErrorOnDetectConnection();
                }
                else
                {
                    initializeCameraAndServices();
                }
            }

            PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
                
            MainController.Singleton.OnNavigatedTo();
#if DEBUG
            if (!rendering)
            {
                CompositionTarget.Rendering += CompositionTarget_Rendering;
                rendering = true;
            }
#endif
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);

            MainController.Singleton.OnNavigatedFrom();

            _cameraSemaphore.WaitOne(100);
            uninitializeCamera();
            _cameraSemaphore.Release();

#if DEBUG
            CompositionTarget.Rendering -= CompositionTarget_Rendering;
            rendering = false;
#endif
        }

        protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
        {
            if (ViewNewMenu.CurrentState == AppBar.State.Open)
            {
                ViewNewMenu.UpdateState();
                e.Cancel = true;
            }
            else
            {

                try
                {
                    if (isConnecting)
                    {
                        e.Cancel = false;
                        base.OnBackKeyPress(e);

                    }
                    else if (isConnected)
                    {
                        e.Cancel = true;
                        base.OnBackKeyPress(e);

                        Thread thread = new Thread(() =>
                        {
                            MainController.Singleton.OnBackKeyPressed(Dispatcher);
                        });
                        thread.IsBackground = false;
                        thread.Start();
                    }
                        //else if (capturingSemaphore)
                        //{
                        //    var result = MessageBox.Show("Photo is being saved, do you really want to exit?", "Saving in process", MessageBoxButton.OKCancel);
                        //    if (result == MessageBoxResult.Cancel)
                        //    {
                        //        e.Cancel = true;
                        //    }
                        //}
                    else
                    {
                        e.Cancel = false;
                        base.OnBackKeyPress(e);
                    }
                }
                catch (Exception erroBack)
                {
                    UpdateMessageForUI(erroBack.Message, AppResources.Error_Back);
                }
            }
        }

        private void ChangeState(StateDictionary param) {
            Dispatcher.BeginInvoke(() =>
            {
            if (MainController.Singleton.NoTap && stateDictionary.getInstance().nameStateReal.ToUpper().Equals("PRETAP"))
            {
                param = stateDictionary.NoTap();
            }

            if (MainController.Singleton.NoTap && stateDictionary.getInstance().nameStateReal.ToUpper().Equals("PRETAPSPLIT"))
            {
                param = stateDictionary.NoTapSplit();
            }



            capturing = param.capturing;
            isConnecting = param.isConnecting;
            isConnected = param.isConnected;
            image_Copy.Visibility = param.isConnecting ? Visibility.Visible : Visibility.Collapsed;
            MyFriendsLabel1.Visibility = param.FriendVisible == true ? Visibility.Visible : Visibility.Collapsed;

            switch (param.nameStateReal)
            {
                case "NoTap":
                case "NoTapSplit":
                    textBlock3.Text = AppResources.MainView_Recharge;
                    textBlock2.Visibility = Visibility.Collapsed;
                    Text.Margin = new Thickness(-80, 80, 0, 0);
                    break;
                case "PreTap":
                case "PreTapSplit":
                    textBlock3.Text = AppResources.MainView_TapThePhones;
                    textBlock2.Visibility = Visibility.Visible;
                    Text.Margin = new Thickness(-80, 60, 0, 0);
                    break;
                case "Connecting":
                case "ConnectingSplit":
                    textBlock3.Text = AppResources.MainView_Connecting ;
                    textBlock2.Visibility = Visibility.Collapsed;
                    Text.Margin = new Thickness(-80, 80, 0, 0);
                    break;
            }

 

           
                CircleControl.TextStatus.Text = param.circleStateText;
                        
                MyFriendsLabel1.Text = param.myFriendsLabelText;

                if (stateDictionary.getInstance().nameStateReal.ToUpper().Equals("NOTAP"))
                {
                    CircleControl.TextStatus.Visibility = System.Windows.Visibility.Visible;
                }

                if (param.isSplit)
                    CircleControl.Visibility = System.Windows.Visibility.Collapsed;

                if (param.playStoryBoard)
                    circleControlTextInStoryboard.Begin();

                if (!capturingSemaphore)
                {
                    ButtonShootMyView.IsEnabled = param.cameraButtonState;
                    ButtonGallery.IsEnabled = param.galleryButtonState;
                }

                PhotoSecurityLock = param.cameraLockState;
                    

                FTU.UpdateState(param.stateName);
                VisualStateManager.GoToState(this, param.stateName, true);
                VisualStateManager.GoToState(CircleControl, param.circleState, true);
            });              
            
        }

        public void AppBar_NavigateToPageEvent(object sender, EventArgs e)
        {
            NavigationService.Navigate(((NavigationEventArgs)e).Uri);
        }

    }
}
